#include "Ahero.hh"

Ahero::Ahero() {
    return;
}

Ahero::Ahero(const Ahero& other) :
    ICharacter(other),
    skill1_targets(other.skill1_targets),
    skill2_targets(other.skill2_targets),
    name(other.name),
    description(other.description),
    is_dead(other.is_dead),
    is_dying(other.is_dying),
    maxHealth(other.maxHealth),
    health(other.health),
    min_attack(other.min_attack),
    max_attack(other.max_attack),
    speed(other.speed),
    round_speed(other.round_speed),
    position_inteam(other.position_inteam),
    stress(other.stress),
    round_finsh(other.round_finsh),
    skill1_description(other.skill1_description),
    skill2_description(other.skill2_description),
    skill1_name(other.skill1_name),
    skill2_name(other.skill2_name),
    crit(other.crit),
    blight(other.blight),
    bleed(other.bleed),
    stun(other.stun),
    deathBlow(other.deathBlow),
    trap(other.trap),
    dodge(other.dodge)
{}

Ahero& Ahero::operator=(const Ahero& other) {
    if (this != &other) {
        ICharacter::operator=(other);
        skill1_targets = other.skill1_targets;
        skill2_targets = other.skill2_targets;
        name = other.name;
        description = other.description;
        is_dead = other.is_dead;
        is_dying = other.is_dying;
        maxHealth = other.maxHealth;
        health = other.health;
        min_attack = other.min_attack;
        max_attack = other.max_attack;
        speed = other.speed;
        round_speed = other.round_speed;
        position_inteam = other.position_inteam;
        stress = other.stress;
        round_finsh = other.round_finsh;
        skill1_description = other.skill1_description;
        skill2_description = other.skill2_description;
        skill1_name = other.skill1_name;
        skill2_name = other.skill2_name;
        crit = other.crit;
        blight = other.blight;
        bleed = other.bleed;
        stun = other.stun;
        deathBlow = other.deathBlow;
        trap = other.trap;
        dodge = other.dodge;
    }
    return *this;
}

bool Ahero::isAlive() const {
    return !this->is_dead;
}

void Ahero::takeDamage(unsigned damage) {
    if (this->health <= damage && !this->is_dying)
    {
        this->health = 0;
        this->is_dying = true;
    } else if(this->is_dying) {
        this->health = 0;
        if (!randomFunc::get_persent_bool(this->deathBlow)) {
            this->is_dead = true;
            this->round_finsh = true;
        }
    } else {
        this->health -= damage;
    }
}

void Ahero::healing(unsigned healing_amount) {
    if (this->health + healing_amount > this->maxHealth) {
        this->health = this->maxHealth;
    } else {
        this->health += healing_amount;
    }
    this->is_dying = false;
}
void Ahero::takeStress(unsigned stress_damage) {
    std::string sentence2return = "";
    this->stress += stress_damage;
    if (this->stress > 150) {
        sentence2return += this->name + "'s faith was being tested...\n";
        if (randomFunc::get_persent_bool(25)) {//美德概率25，需要引用设置
            this->health = this->maxHealth;
            sentence2return += "Virtue!\n";
        } else {
            if (this->health > (this->maxHealth * 0.1)) {
                this->health = this->maxHealth * 0.1;
            }
            sentence2return += "Affliction!\n";
        }
        this->stress = 10;
    }
    std::cout << sentence2return;
}

void Ahero::stressHealing(unsigned healing_amount) {
    if (this->stress <= healing_amount) {
        this->stress = 0;
    } else {
        this->stress -= healing_amount;
    }
}

// void Ahero::takeBuff(buff_and_effect::Abuff& buff) {
//     bool have_buff = false;
//     for (auto iterator = this->buffs.begin(); iterator != this->buffs.end(); ++iterator){
//         if(*iterator == buff){
//            *iterator += buff;
//            have_buff = true;
//            break;
//         }
//     }
//     if (!have_buff) {
//         this->buffs.push_back(buff);
//     }
// }

// void Ahero::removeBuff(buff_and_effect::Abuff& buff) {
//     for (auto iterator = this->buffs.begin(); iterator != this->buffs.end(); ++iterator){
//         if(*iterator == buff){
//             this->buffs.erase(iterator);
//             break;
//         }
//     } 
// }

void Ahero::modifyRoundSpeed(int new_speed) {
    this->round_speed = new_speed;
}

void Ahero::sitRoundFinsh(bool b) {
    this->round_finsh = b;
}

void Ahero::changePosInteam(unsigned new_pos) {
    this->position_inteam = new_pos;
}
unsigned Ahero::getSkillName() {
    int num;
    bool get_num = false;

    while (!get_num) {
        std::cout << "Enter 1 to use " << this->skill1_description << "\n";
        std::cout << "Enter 2 to use " << this->skill2_description << "\n";
        std::cin >> num;
        if (num < 1|| num > 2 || std::cin.fail()) {
            std::cin.clear();
            std::cin.ignore(1000, '\n');
            std::cout << "Value should be " << 1 << " or " << 2 << "\n";
        } else {
            get_num = true;
        }
    }
    
    num = static_cast<unsigned int>(num);
    return num;
}
unsigned Ahero::getskill1Target() {
    int num;
    bool get_num = false;

    while (!get_num) {
        std::cout << "Input a postion between " << *this->skill1_targets.begin() + 1 << " and " << this->skill1_targets.back() + 1 << "\n";
        std::cin >> num;
        if (num < *this->skill1_targets.begin() + 1 || num > this->skill1_targets.back() + 1 || std::cin.fail()) {
            std::cin.clear();
            std::cin.ignore(1000, '\n');
            std::cout << "Value should between " << *this->skill1_targets.begin() + 1 << " and " << this->skill1_targets.back() + 1 << "\n";
        } else {
            get_num = true;
        }
    }
    
    num = static_cast<unsigned int>(num);
    return num - 1;
}

unsigned Ahero::getskill2Target() {
    int num;
    bool get_num = false;

    while (!get_num) {
        std::cout << "Input a postion between " << *this->skill2_targets.begin() + 1 << " and " << this->skill2_targets.back() + 1 << "\n";
        std::cin >> num;
        if (num < *this->skill2_targets.begin() + 1 || num > this->skill2_targets.back() + 1 || std::cin.fail()) {
            std::cin.clear();
            std::cin.ignore(1000, '\n');
            std::cout << "Value should between " << *this->skill2_targets.begin() + 1 << " and " << this->skill2_targets.back() + 1 << "\n";
        } else {
            get_num = true;
        }
    }
    
    num = static_cast<unsigned int>(num);
    return num - 1;
}
void Ahero::changeAttack(int change_num) {
    if (min_attack > -change_num) {
        this->min_attack += change_num;
        this->max_attack += change_num;
    }
}

void Ahero::changeSpeed(int change_num) {
    this->speed += change_num;
}
// Getters
std::string Ahero::getName() const {
    return this->name;
}
std::string Ahero::getDescription() const {
    return this->description;
}
unsigned Ahero::getMaxHealth() const {
    return this->maxHealth;
}
unsigned Ahero::getHealth() const {
    return this->health;
}
unsigned Ahero::getMinAttack() const {
    return this->min_attack;
}
unsigned Ahero::getMaxAttack() const {
    return this->max_attack;
}
unsigned Ahero::getSpeed() const {
    return this->speed;
}
int Ahero::getRoundSpeed() const {
    return this->round_speed;
}
unsigned Ahero::getPosInteam() const {
    return this->position_inteam;
}
unsigned Ahero::getStress() const {
    return this->stress;
}
// std::vector<buff_and_effect::Abuff> Ahero::getBuffs() const {
//     return this->buffs;
// }
bool Ahero::getRoundFinsh() const {
    return this->round_finsh;
}
std::string Ahero::getskill1_description() const {
    return this->skill1_description;
}
std::string Ahero::getskill2_description() const {
    return this->skill2_description;
}
std::string Ahero::getskill1_name() const {
    return this->skill1_name;
}
std::string Ahero::getskill2_name() const {
    return this->skill2_name;
}

unsigned Ahero::getCrit() const {
    return this->crit;
}
unsigned Ahero::getBlight() const {
    return this->blight;
}
unsigned Ahero::getBleed() const {
    return this->bleed;
}
unsigned Ahero::getStun() const {
    return this->stun;
}
unsigned Ahero::getDeathBlow() const {
    return this->deathBlow;
}
unsigned Ahero::getTrap() const {
    return this->trap;
}
unsigned Ahero::getDodge() const {
    return this->dodge;
}

std::string Ahero::toString() const {
    std::string sentens = "";
    if (!this->round_finsh) {
        sentens += "! ";
    }
    sentens += this->name + " hp: (" + std::to_string(this->health) + "/" + std::to_string(this->maxHealth) + ") " + " stress: " + std::to_string(this->stress) + "/150\n";//150为压力上限，需引用setting
    // for (auto &buff : this->buffs) {
    //     sentens += buff.samllInfo();
    // } 
    if (this->is_dying) {
        sentens += " (Dying!)";
    }
    if (this->is_dead) {
        sentens += " (Dead body)";
    }
    return sentens;
}
// Operator overloads
Ahero& Ahero::operator-=(unsigned damage) {
    this->takeDamage(damage);
    return *this;
} // For taking damage
Ahero& Ahero::operator+=(unsigned healing_amount) {
    this->healing(healing_amount);
    return *this;
} //治疗 

std::ostream& operator<<(std::ostream& os, const Ahero& Ahero) {
    os << Ahero.getDescription();
    return os;
}